package com.mouse.magent.common.handler;

import com.mouse.magent.common.protocol.Command;
import com.mouse.magent.common.protocol.Message;
import com.mouse.magent.common.service.BaseAction;
import com.mouse.magent.common.service.BaseCommandAction;
import com.mouse.magent.common.util.NettyUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 基础处理器
 */
@Slf4j
@ChannelHandler.Sharable
public class BaseHandler extends SimpleChannelInboundHandler<Message> {
    @Getter
    @Setter
    private DefaultChannelGroup channelGroup;
    @Getter
    @Setter
    private List<BaseCommandAction> commandActionList;

    public BaseHandler() {
    }

    public BaseHandler(DefaultChannelGroup channelGroup, List<BaseCommandAction> commandActionList) {
        this.channelGroup = channelGroup;
        this.commandActionList = commandActionList;
    }


    private static Map<Command, BaseAction> actionList = null;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message message) throws Exception {
        if (actionList == null) {
            actionList = new HashMap<>();
            commandActionList.forEach(messageAction -> actionList.put(messageAction.getCommand(), messageAction.getAction()));
        }
        if (Command.KEEP_ALIVE.equals(message.getType())) {
            return;
        }
        BaseAction action = actionList.get(message.getType());
        if (action == null) {
            log.info("message type异常");
            return;
        }
        try {
            action.handle(ctx, message);
        } catch (Exception e) {
            log.error(e.getMessage(), e);

            if (action.returnLog()) {
                message.getHeader().setSuccess(0);
                StringBuffer errorSb = new StringBuffer();
                errorSb.append(e.toString() + "\n");
                StackTraceElement[] elements = e.getStackTrace();
                for (int i = 0; i < elements.length; i++) {
                    errorSb.append("\t" + elements[i].toString());
                    if (i != elements.length - 1) errorSb.append("\n");
                }
                message.getHeader().setResult(errorSb.toString());
                ctx.writeAndFlush(message);
            }
        } finally {
            if (action.systemExit()) {
                log.info("关闭");
                System.exit(0);
            }
        }

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("ip:{} Exception caught: {}", NettyUtil.getRemoteIp(ctx), cause.getMessage());
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                log.info("ip:{} Read idle loss connection.", NettyUtil.getRemoteIp(ctx));
                ctx.close();
            } else if (e.state() == IdleState.WRITER_IDLE) {
                Message natxMessage = new Message();
                natxMessage.setType(Command.KEEP_ALIVE);
                ctx.writeAndFlush(natxMessage);
            }
        }
    }
}
